﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace XNAFight.Engine
{
    public class SpriteManager
    {
        // Définition du sprite
        // -----------------------------------------
        private Texture2D texture;  // texture contenant toute la spritesheet
        private Vector2 position;   // position qui indique à quel endroit afficher le sprite
        private Vector2 center;     // centre du rectangle contenant une étape d'animation
        private Vector2 origine;    // point de référence pour l'affichage (point du sprite relatif à son coin haut gauche, qui va être affiché sur la position)
        
        private Rectangle rectFrame;
        private int frameWidth;
        private int frameHeight;

        // Effets éventuels
        private Color color;
        private float depth;
        private float scale;
        private float rotation;
        private SpriteEffects sprite_effect;

        // Animation
        private int nbFrames;
        private int startFrame;
        private int endFrame;
        private float timeParFrame;
        
        // Agencement de la spritesheet
        private int nbLignesSprites;
        private int nbSpritesMaxParLigne;
        // -----------------------------------------
        

        // Logique interne
        // -----------------------------------------
        private bool paused;
        private int sensAnim;       // -1 signifie qu'on est à l'envers, 1 à l'endroit
        private bool loop;
        private bool yoyo;
        private bool finAnim;       // true uniquement lorsqu'une anime non loop affiche sa dernière frame
        private int frame;          // étape d'animation en cours (celle qui doit être affichée)
        private float totalElapsed;

        private float oldDepth;
        // -----------------------------------------

        public SpriteManager(Texture2D loadedTexture, Vector2 gameObjectPosition, float gameObjectDepth)
        {
            texture = loadedTexture;
            center = new Vector2(texture.Width / 2, texture.Height / 2);
            position = gameObjectPosition;
            
            
            depth = gameObjectDepth;
            oldDepth = gameObjectDepth;

            scale = 1.0f;
            rotation = 0;
            color = Color.White;

            sprite_effect = SpriteEffects.None;

            rectFrame = new Rectangle(0, 0, texture.Width, texture.Height);
            nbFrames = 1;
            frameWidth = texture.Width / nbFrames;
            startFrame = 0;
            endFrame = 0;
            frame = 0;
            paused = true;
            sensAnim = 1;
            totalElapsed = 0;
            loop = false;
            yoyo = false;

            finAnim = false;

            timeParFrame = 1.0f;
        }
        
        public SpriteManager(Texture2D loadedTexture, Vector2 gameObjectPosition, float gameObjectDepth, int nombreFrames, int _largeurSprite, Vector2 _origine)
        {
            
            
            texture = loadedTexture;
            position = gameObjectPosition;
            origine = _origine;
            frameWidth = _largeurSprite;
            depth = gameObjectDepth;
            oldDepth = gameObjectDepth;
            nbFrames = nombreFrames;
            scale = 1.0f;
            rotation = 0;
            color = Color.White;
            sprite_effect = SpriteEffects.None;

            nbSpritesMaxParLigne = texture.Width / frameWidth;
            nbLignesSprites = nbFrames / nbSpritesMaxParLigne;
            if ((nbFrames % nbSpritesMaxParLigne) > 0) nbLignesSprites++;
            frameHeight = texture.Height / nbLignesSprites;

            rectFrame = new Rectangle(0, 0, frameWidth, frameHeight);
            
            center = new Vector2(frameWidth / 2, frameHeight / 2);
            startFrame = 0;
            endFrame = 0;
            frame = 0;
            paused = true;
            sensAnim = 1;
            totalElapsed = 0;
            loop = false;

            finAnim = false;

            timeParFrame = 1.0f;
        }

        public void updateFrame(float elapsed)
        {
            if (paused)
                return;

            if (nbFrames <= 1)
                return;

            totalElapsed += elapsed;

            if (totalElapsed >= timeParFrame)
            {
                frame += sensAnim;

                if (frame > endFrame)
                {
                    if (yoyo)
                    {
                        frame = endFrame - 1;
                        sensAnim = -1;
                    }
                    else
                    {
                        if (loop)
                        {
                            frame = startFrame;
                        }
                        else
                        {
                            frame = endFrame;
                            pause();
                            finAnim = true;
                        }
                    }
                }
                else if (frame < startFrame)
                {
                    if (loop)
                    {
                        if (yoyo)
                        {
                            frame = startFrame + 1;
                            sensAnim = 1;
                        }
                        else
                        {
                            frame = endFrame;
                        }
                    }
                    else
                    {
                        frame = startFrame;
                        pause();
                        finAnim = true;
                    }
                }

                totalElapsed = 0.0f;
            }

        }

        public void draw(SpriteBatch spriteBatch)
        {         
            rectFrame.X = frameWidth * (frame % nbSpritesMaxParLigne);
            rectFrame.Y = frameHeight * (frame / nbSpritesMaxParLigne);
            rectFrame.Width = frameWidth;
            rectFrame.Height = frameHeight;
            
            spriteBatch.Draw(texture, position, rectFrame, color, rotation, origine, scale, sprite_effect, depth);
        }


        #region PROPRIETES
        public bool Loop
        {
            get { return loop; }
        }
        public int StartFrame
        {
            get { return startFrame; }
        }
        public int CurrentFrame
        {
            get { return frame; }
        }
        public int NbFrames
        {
            get { return nbFrames; }
            set { nbFrames = value; }
        }
        public float Scale
        {
            get { return scale; }
            set { scale = value; }
        }
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }
        public SpriteEffects Sprite_effect
        {
            get { return sprite_effect; }
            set { sprite_effect = value; }
        }
        public bool FinAnim
        {
            get { return finAnim; }
        }
        public Vector2 Origine
        {
            get { return origine; }
        }
        #endregion

        public void changeDepth(float newDepth)
        {
            oldDepth = depth;
            depth = newDepth;
        }

        public void resetDepth()
        {
            depth = oldDepth;
        }

        public void changeAlpha(byte newAlpha)
        {
            color.A = newAlpha;
        }

        public void switchTexture(Texture2D _texture, int _nbFrames, int _widthFrame)
        {
            texture = _texture;
            nbFrames = _nbFrames;
            frameWidth = _widthFrame;

            nbSpritesMaxParLigne = texture.Width / frameWidth;
            nbLignesSprites = nbFrames / nbSpritesMaxParLigne;
            if ((nbFrames % nbSpritesMaxParLigne) > 0) nbLignesSprites++;
            frameHeight = texture.Height / nbLignesSprites;

            rectFrame = new Rectangle(0, 0, frameWidth, frameHeight);

            center = new Vector2(frameWidth / 2, frameHeight / 2);
        }

        public void animSimple(int start, int end, float tempsAnime)
        {
            startFrame = start;
            endFrame = end;
            frame = start;
            loop = false;
            //timeParFrame = (float)1 / framePerSec;
            timeParFrame = (float)tempsAnime / (end - start);
            sensAnim = 1;
            totalElapsed = 0.0f;
            yoyo = false;

            play();
        }

        public void animSimple(int start, int end, float tempsAnime, bool boucle, bool sensInverse)
        {
            startFrame = start;
            endFrame = end;
            loop = boucle;
            timeParFrame = (float)tempsAnime / (end - start);
            if (sensInverse)
            {
                sensAnim = -1;
                frame = end;
            }
            else
            {
                sensAnim = 1;
                frame = start;
            }
            totalElapsed = 0.0f;
            yoyo = false;

            play();
        }

        public void animYoyo(int start, int end, float tempsAnime, bool boucle)
        {
            startFrame = start;
            endFrame = end;
            frame = start;
            loop = boucle;
            timeParFrame = (float)tempsAnime / (end - start);
            sensAnim = 1;
            totalElapsed = 0.0f;
            yoyo = true;

            play();
        }

        public void animFixe(int numFrame)
        {
            frame = numFrame;
        }
        
        public void play()
        {
            paused = false;
            finAnim = false;
        }
        public void pause()
        {
            paused = true;
        }

        public bool isPaused()
        {
            return paused;
        }

        

        public Rectangle getRectAffiche()
        {
            Rectangle rect = new Rectangle((int)(position.X - center.X), (int)(position.Y - center.Y), rectFrame.Width, rectFrame.Height);
            return rect;
        }

        public Color[] getDataTextureAffiche()
        {
            Color[] tableauDatas;
            tableauDatas = new Color[rectFrame.Width * rectFrame.Height];
            texture.GetData(0, rectFrame, tableauDatas, 0, rectFrame.Width * rectFrame.Height);

            return tableauDatas;
        }
        
    }
}
